/* This Component Library is licensed under the GNU General Public License version 2 (GPLv2) 
 * You can use this software and its associated files as you wish so long as derived versions
 * or works based on this library are also freely released.
 * If you require a commercial licence for this software without the above restrictions please
 * contact me via scott_blood@hotmail.com or via CodePlex.
 * (c) 2010 Scott Blood
 * Visit SGBControls.CodePlex.com for the latest version of this library.
 */ 
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Collections.Specialized;
using SGBControls.Functions;
using System.Collections.Generic;

namespace SGBControls.Editors
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(TextBox))]
    [DefaultBindingPropertyAttribute("Text")]
	public class SGBTextBox : SGBBaseControl
    {
        #region Event Delegates
        public event EventHandler AcceptsTabChanged;
        public new event EventHandler BorderStyleChanged;
        public new event EventHandler Click;
        public new event EventHandler DoubleClick;
        public event EventHandler HideSelectionChanged;
        public new event KeyEventHandler KeyDown;
        public new event KeyEventHandler KeyUp;
        public new event KeyPressEventHandler KeyPress;
        public new event MouseEventHandler MouseDown;
        public new event MouseEventHandler MouseUp;
        public new event MouseEventHandler MouseMove;
        public new event EventHandler MouseHover;
        public new event EventHandler MouseLeave;
        public new event MouseEventHandler MouseWheel;
        public new event PreviewKeyDownEventHandler PreviewKeyDown;
        [Browsable(true)]
        public new event EventHandler TextChanged;
        public event EventHandler MultiLineChanged;
        public new event EventHandler ForeColorChanged;
        public event EventHandler ReadOnlyChanged;
        public event ClipboardOperationEventHandler ClipboardOperation;                
        
        private void HookUpEvents()
        {
            
        }
        #endregion

        #region Private Variables
        //private Color fBorderColor = Color.LightSteelBlue;
        //private BorderStyles fBorderStyle = BorderStyles.Flat;
        //private SGBEditStyleController fStyleController = null;
        private SGBBaseTextBox fTextBoxControl;
        private System.ComponentModel.Container components = null;
        private InputTypes fInputType = InputTypes.Default;
        private int fAutoCompleteThreshold = 3;
        private AutoCompleteSource fAutoCompleteOldSource = AutoCompleteSource.None;
     
        #endregion

        #region Standard TextBox Properties

        [Description("Gets or sets the current text in the text box.")]
        public override string Text
        {
            get
            {
                return this.fTextBoxControl.Text;
            }
            set
            {
                this.fTextBoxControl.Text = value;
            }
        }

        [Description("Gets or sets the foreground color of the control.")]
        public override Color ForeColor
        {
            get
            {
                return this.fTextBoxControl.ForeColor;
            }
            set
            {
                this.fTextBoxControl.ForeColor = value;
            }
        }

        [Description("Gets or sets the shortcut menu associated with the control.")]
        public override ContextMenu ContextMenu
        {
            get
            {
                return this.fTextBoxControl.ContextMenu;
            }
            set
            {
                this.fTextBoxControl.ContextMenu = value;
            }
        }


        [Description("Gets or sets a value indicating whether pressing ENTER in a multiline TextBox control creates a new line of text in the control or activates the default button for the form.")]
        public bool AcceptsReturn
        {
            get
            {
                return fTextBoxControl.AcceptsReturn;
            }
            set
            {
                fTextBoxControl.AcceptsReturn = value;
            }
        }

        [Description("Gets or sets a value indicating whether pressing the TAB key in a multiline text box control types a TAB character in the control instead of moving the focus to the next control in the tab order.")]
        public bool AcceptsTab
        {
            get
            {
                return fTextBoxControl.AcceptsTab;
            }
            set
            {
                fTextBoxControl.AcceptsTab = value;                
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Editor("System.Windows.Forms.Design.StringCollectionEditor", "System.Drawing.Design.UITypeEditor, System.Drawing")]
        [Description("Gets or sets a customer StringCollection to use when the AutoCompleteSource property is set to CustomSource")]
        public AutoCompleteStringCollection AutoCompleteCustomSource
        {
            get
            {                
                return fTextBoxControl.AutoCompleteCustomSource;
            }
            set
            {
                fTextBoxControl.AutoCompleteCustomSource = value;
            }
        }

        [Description("Gets or sets an option that controls how automatic completion works for the TextBox.")]
        public AutoCompleteMode AutoCompleteMode
        {
            get
            {
                return fTextBoxControl.AutoCompleteMode;
            }
            set
            {
                fTextBoxControl.AutoCompleteMode = value;
            }
        }

        [Description("Gets or sets a value specifying the source of complete strings used for automatic completion.")]
        public AutoCompleteSource AutoCompleteSource
        {
            get
            {
                return fTextBoxControl.AutoCompleteSource;
            }
            set
            {
                fTextBoxControl.AutoCompleteSource = value;
            }
        }

        [Description("Gets or sets whether the TextBox control modifies the case of characters as they are typed.")]
        public CharacterCasing CharacterCasing
        {
            get
            {
                return fTextBoxControl.CharacterCasing;
            }
            set
            {
                fTextBoxControl.CharacterCasing = value;
            }
        }

        [Description("Gets or sets a value indicating whether the selected text in the text box control remains highlighted when the control loses focus.")]
        public bool HideSelection
        {
            get
            {
                return fTextBoxControl.HideSelection;
            }
            set
            {
                fTextBoxControl.HideSelection = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int MaxLength
        {
            get
            {
                return fTextBoxControl.MaxLength;
            }
            set
            {
                fTextBoxControl.MaxLength = value;
            }
        }

        public bool MultiLine
        {
            get
            {
                return fTextBoxControl.Multiline;
            }
            set
            {
                fTextBoxControl.Multiline = value;
            }
        }

        [Description("Gets or sets the character used to mask characters of a password in a single-line TextBox control.")]
        public char PasswordChar
        {
            get
            {
                return fTextBoxControl.PasswordChar;
            }
            set
            {
                fTextBoxControl.PasswordChar = value;
            }
        }

        [Description("Gets or sets a value indicating whether text in the text box is read-only.")]
        public bool ReadOnly
        {
            get
            {
                return fTextBoxControl.ReadOnly;
            }
            set
            {
                fTextBoxControl.ReadOnly = value;
            }
        }

        [Description("Gets or sets which scroll bars should appear in a multiline TextBox control.")]
        public ScrollBars Scrollbars
        {
            get
            {
                return fTextBoxControl.ScrollBars;
            }
            set
            {
                fTextBoxControl.ScrollBars = value;                
            }
        }

        [Description("Gets or sets a value indicating whether the defined shortcuts are enabled.")]
        public bool ShortcutsEnabled
        {
            get
            {
                return fTextBoxControl.ShortcutsEnabled;
            }
            set
            {
                fTextBoxControl.ShortcutsEnabled = value;
            }
        }

        [Description("Gets or sets how text is aligned in a TextBox control.")]
        public HorizontalAlignment TextAlign
        {
            get
            {
                return fTextBoxControl.TextAlign;
            }
            set
            {
                fTextBoxControl.TextAlign = value;
            }
        }

        [Description("Gets or sets a value indicating whether the text in the TextBox control should appear as the default password character.")]
        public bool UseSystemPasswordChar
        {
            get
            {
                return fTextBoxControl.UseSystemPasswordChar;
            }
            set
            {
                fTextBoxControl.UseSystemPasswordChar = value;
            }
        }

        [Description("Indicates whether a multiline text box control automatically wraps words to the beginning of the next line when necessary.")]
        public bool WordWrap
        {
            get
            {
                return fTextBoxControl.WordWrap;
            }
            set
            {
                fTextBoxControl.WordWrap = value;                
            }
        }

        [Description("Gets or sets the lines of text in a text box control.")]
        public string[] Lines
        {
            get
            {
                return fTextBoxControl.Lines;
            }
            set
            {
                fTextBoxControl.Lines = value;
            }
        }

        [Browsable(false)]
        [Description("Gets a value indicating whether the user can undo the previous operation in a text box control.")]
        public bool CanUndo
        {
            get
            {
                return fTextBoxControl.CanUndo;                                
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Gets or sets a value indicating the currently selected text in the control.")]        
        public string SelectedText
        {
            get
            {
                return fTextBoxControl.SelectedText;
            }
            set
            {
                fTextBoxControl.SelectedText = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Gets or sets the number of characters selected in the text box.")]
        public int SelectionLength
        {
            get
            {
                return fTextBoxControl.SelectionLength;
            }
            set
            {
                fTextBoxControl.SelectionLength = value;                
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Gets or sets the starting point of text selected in the text box.")]
        public int SelectionStart
        {
            get
            {
                return fTextBoxControl.SelectionStart;
            }
            set
            {
                fTextBoxControl.SelectionStart = value;
            }
        }


        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Browsable(false)]
        [Description("Gets the length of text in the control.")]
        public int TextLength
        {
            get
            {
                return fTextBoxControl.TextLength;
            }
        }

        [Description("Gets or sets the background color of the text box")]
        public override Color BackColor
        {
            get
            {
                return fTextBoxControl.BackColor;
            }
            set
            {
                fTextBoxControl.BackColor = value;
            }
        }
        
        #endregion

        #region Standard Textbox Methods
        [Description("Appends text to the current text of text box.")]
        public void AppendText(string text)
        {
            fTextBoxControl.AppendText(text);            
        }

        [Description("Clears all text from the text box control.")]
        public void Clear()
        {
            fTextBoxControl.Clear();
        }

        [Description("Clears information about the most recent operation from the undo buffer of the text box.")]
        public void ClearUndo()
        {
            fTextBoxControl.ClearUndo();
        }

        [Description("Copies the current selection in the text box to the Clipboard.")]
        public void Copy()
        {
            fTextBoxControl.Copy();
        }

        [Description("Moves the current selection in the text box to the Clipboard.")]
        public void Cut()
        {
            fTextBoxControl.Cut();
        }

        [Description("Replaces the current selection in the text box with the contents of the Clipboard.")]
        public void Paste()
        {
            fTextBoxControl.Paste();
            //if (ClipboardOperation != null)
            //    ClipboardOperation(this, new EditorEvents.ClipboardOperationHandler(ClipboardOperationType.Paste));
        }

        [Description("Resets the Text property to its default value.")]
        public new void ResetText()
        {
            fTextBoxControl.ResetText();
        }

        [Description("Scrolls the contents of the control to the current caret position.")]
        public void ScrollToCaret()
        {
            fTextBoxControl.ScrollToCaret();            
        }

        [Description("Selects text within the control.")]
        public void Select(int start, int length)
        {
            fTextBoxControl.Select(start, length);
        }

        [Description("Selects all text in the text box.")]
        public void SelectAll()
        {
            fTextBoxControl.SelectAll();
        }

        [Description("Undoes the last edit operation in the text box.")]
        public void Undo()
        {
            fTextBoxControl.Undo();            
        }

        [Description("Specifies that the value of the SelectionLength property is zero so that no characters are selected in the text box.")]
        public void DeSelectAll()
        {
            fTextBoxControl.DeselectAll();
        }

        [Description("Retrieves the character that is closest to the specified location within the text box.")]
        public void GetCharFromPosition(Point pt)
        {
            fTextBoxControl.GetCharFromPosition(pt);
        }

        [Description("Retrieves the index of the character nearest to the specified location.")]
        public int GetCharIndexFromPosition(Point pt)
        {
            return fTextBoxControl.GetCharIndexFromPosition(pt);
        }

        [Description("Retrieves the index of the first character of a given line.")]
        public int GetFirstCharIndexFromLine(int lineNumber)
        {
            return fTextBoxControl.GetFirstCharIndexFromLine(lineNumber);
        }

        [Description("Retrieves the index of the first character of the current line.")]
        public int GetFirstCharIndexOfCurrentLine()
        {
            return fTextBoxControl.GetFirstCharIndexOfCurrentLine();
        }

        [Description("Retrieves the location within the control at the specified character index.")]
        public Point GetPositionFromCharIndex(int index)
        {
            return fTextBoxControl.GetPositionFromCharIndex(index);
        }


        #endregion
          
        #region New Properties

        //[Description("Gets or sets the number of characters that must be type before the auto complete features are initiated on the Edit Control.")]
        //public int AutoCompleteThreshold
        //{
        //    get
        //    {
        //        return fAutoCompleteThreshold;
        //    }
        //    set
        //    {
        //        fAutoCompleteThreshold = value;
        //    }
        //}
       

        void fStyleController_Invalidated(object sender, EventArgs e)
        {
            Invalidate();
        }        
        
        [Description("Gets or sets the input type used to limit input in the Edit Control.")]
        public InputTypes InputType
        {
            get
            {
                return fInputType;
            }
            set
            {
                fInputType = value;
            }
        }        
        #endregion        

        #region New Methods

        [Description("Gets the native .net TextBox used to render this control.")]
        public override object GetNativeControl()
        {
            return fTextBoxControl.GetNativeControl();
        }

        [Description("Converts the text within the text box control into the specified case.")]
        public void ChangeCase(TextCase caseType)
        {
            switch (caseType)
            {
                case TextCase.Lowercase:
                    fTextBoxControl.Text = fTextBoxControl.Text.ToLower();
                    break;
                case TextCase.Uppercase:
                    fTextBoxControl.Text = fTextBoxControl.Text.ToUpper();
                    break;
                case TextCase.ProperCase:
                    fTextBoxControl.Text = StringFunction.ToProperCase(fTextBoxControl.Text);
                    break;
            }
        }

        [Description("Returns the index of the first occourence of the specified text.")]
        public int FindText(string text)
        {            
            return fTextBoxControl.Text.ToUpper().IndexOf(text.ToUpper());
        }

        [Description("Returns the index of the first occourence of the specified text starting from the position specified")]
        public int FindText(string text, int startIndex)
        {                        
            return fTextBoxControl.Text.ToUpper().IndexOf(text.ToUpper(), startIndex);
        }

        public int[] FindAllInstancesOfText(string text)
        {
            List<int> FoundIndexes = new List<int>();

            int FoundPosition = FindText(text);
            if (FoundPosition > -1) FoundIndexes.Add(FoundPosition);
            while (FoundPosition > -1)
            {
                FoundPosition = FindText(text, FoundPosition + 1);
                if (FoundPosition > -1)
                    FoundIndexes.Add(FoundPosition);
            }

            return FoundIndexes.ToArray();            
        }

        #endregion

        #region constructor

        public SGBTextBox()
		{			
            InitializeComponent();

            fTextBoxControl.AcceptsTabChanged += new EventHandler(fTextBoxControl_AcceptsTabChanged);
            fTextBoxControl.BorderStyleChanged += new EventHandler(fTextBoxControl_BorderStyleChanged);
            fTextBoxControl.Click += new EventHandler(fTextBoxControl_Click);
            fTextBoxControl.DoubleClick += new EventHandler(fTextBoxControl_DoubleClick);
			fTextBoxControl.HideSelectionChanged +=new EventHandler(fTextBoxControl_HideSelectionChanged);
            fTextBoxControl.KeyDown += new KeyEventHandler(fTextBoxControl_KeyDown);
            fTextBoxControl.KeyPress += new KeyPressEventHandler(fTextBoxControl_KeyPress);
            fTextBoxControl.KeyUp += new KeyEventHandler(fTextBoxControl_KeyUp);
            fTextBoxControl.MouseDown += new MouseEventHandler(fTextBoxControl_MouseDown);
            fTextBoxControl.MouseUp += new MouseEventHandler(fTextBoxControl_MouseUp);
            fTextBoxControl.MouseMove += new MouseEventHandler(fTextBoxControl_MouseMove);
            fTextBoxControl.MouseLeave += new EventHandler(fTextBoxControl_MouseLeave);
            fTextBoxControl.MouseHover += new EventHandler(fTextBoxControl_MouseHover);
            fTextBoxControl.MouseWheel += new MouseEventHandler(fTextBoxControl_MouseWheel);
            fTextBoxControl.PreviewKeyDown += new PreviewKeyDownEventHandler(fTextBoxControl_PreviewKeyDown);
            fTextBoxControl.TextChanged += new EventHandler(fTextBoxControl_TextChanged);
            fTextBoxControl.MultilineChanged += new EventHandler(fTextBoxControl_MultilineChanged);
            fTextBoxControl.ForeColorChanged += new EventHandler(fTextBoxControl_ForeColorChanged);
            fTextBoxControl.ReadOnlyChanged += new EventHandler(fTextBoxControl_ReadOnlyChanged);
            fTextBoxControl.ClipboardOperation += new ClipboardOperationEventHandler(fTextBoxControl_ClipboardOperation);
        }        

        #endregion

        #region Event Methods

        void fTextBoxControl_ClipboardOperation(object sender, ClipboardOperationArgs e)
        {
            
            if (ClipboardOperation != null)
                ClipboardOperation(sender, e);
        }

        void fTextBoxControl_ReadOnlyChanged(object sender, EventArgs e)
        {
            if (ReadOnlyChanged != null)
                ReadOnlyChanged(sender, e);
        }

        void fTextBoxControl_ForeColorChanged(object sender, EventArgs e)
        {
            if (ForeColorChanged != null)
                ForeColorChanged(sender, e);
        }

        void fTextBoxControl_MultilineChanged(object sender, EventArgs e)
        {
            if (MultiLineChanged != null)
                MultiLineChanged(sender, e);
        }

        void fTextBoxControl_TextChanged(object sender, EventArgs e)
        {
            if (TextChanged != null)
                TextChanged(sender, e);

            if (fAutoCompleteThreshold != 0)
            {
                if (this.TextLength >= fAutoCompleteThreshold)
                {
                    if (fAutoCompleteOldSource != AutoCompleteSource.None)
                        fAutoCompleteOldSource = fTextBoxControl.AutoCompleteSource;
                    AutoCompleteSource = AutoCompleteSource.None;
                }
                else
                {
                    AutoCompleteSource = fAutoCompleteOldSource;
                }
            }
        }

        void fTextBoxControl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (PreviewKeyDown != null)
                PreviewKeyDown(sender, e);           
        }

        
        
        void fTextBoxControl_MouseWheel(object sender, MouseEventArgs e)
        {
            if (MouseWheel != null)
                MouseWheel(sender, e);
        }

        void fTextBoxControl_MouseHover(object sender, EventArgs e)
        {
            if (MouseHover != null)
                MouseHover(sender, e);
        }

        void fTextBoxControl_MouseLeave(object sender, EventArgs e)
        {
            if (MouseLeave != null)
                MouseLeave(sender, e);
        }

        void fTextBoxControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (MouseMove != null)
                MouseMove(sender, e);
        }

        void fTextBoxControl_MouseUp(object sender, MouseEventArgs e)
        {
            if (MouseUp != null)
                MouseUp(sender, e);
        }

        void fTextBoxControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (MouseDown != null)
                MouseDown(sender, e);
        }                           

        void fTextBoxControl_KeyUp(object sender, KeyEventArgs e)
        {
            if (KeyUp != null)
                KeyUp(sender, e);
        }

        void fTextBoxControl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsControl(e.KeyChar))
            {
                switch (fInputType)
                {
                    case InputTypes.Number:
                        {
                            if (!char.IsNumber(e.KeyChar)) e.Handled = true;
                            break;
                        }
                    case InputTypes.EverythingButNumbers:
                        {
                            if (Char.IsNumber(e.KeyChar)) e.Handled = true;
                            break;
                        }
                    case InputTypes.LettersAndNumbers:
                        {
                            if (!(char.IsNumber(e.KeyChar) || char.IsLetter(e.KeyChar))) e.Handled = true;
                            break;
                        }
                    case InputTypes.LettersOnly:
                        {
                            if (!Char.IsLetter(e.KeyChar)) e.Handled = true;
                            break;
                        }
                }
            }
        
            if (KeyPress != null)
                KeyPress(sender, e);
        }

        void fTextBoxControl_KeyDown(object sender, KeyEventArgs e)
        {
            if (KeyDown != null)
                KeyDown(sender, e);
        }
        

        void  fTextBoxControl_HideSelectionChanged(object sender, EventArgs e)
        {
            if (HideSelectionChanged != null)
                HideSelectionChanged(sender, e);
        }

        void fTextBoxControl_BorderStyleChanged(object sender, EventArgs e)
        {
            if (BorderStyleChanged != null)
                BorderStyleChanged(sender, e);
        }

        void fTextBoxControl_AcceptsTabChanged(object sender, EventArgs e)
        {
            if (AcceptsTabChanged != null)
                AcceptsTabChanged(sender, e);
        }

        void fTextBoxControl_Click(object sender, EventArgs e)
        {
            if (Click != null)
                Click(sender, e);
        }

        void fTextBoxControl_DoubleClick(object sender, EventArgs e)
        {
            if (DoubleClick != null)
                DoubleClick(sender, e);
        }   
        #endregion

        #region Overridden events        
        protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint (e);            
		}

        private void TextBox_SizeChanged(object sender, System.EventArgs e)
        {
            TextBox tb = sender as TextBox;
            this.Height = tb.Height + 8;
        }

        protected override void OnEnter(EventArgs e)
        {
            if (StyleController != null)
            {
                fTextBoxControl.BackColor = StyleController.ActiveBackgroundColor;
                fTextBoxControl.ForeColor = StyleController.ActiveForeColor;
            }
            base.OnEnter(e);
        }

        protected override void OnLeave(EventArgs e)
        {
            if (StyleController != null)
            {
                fTextBoxControl.BackColor = StyleController.InActiveBackgroundColor;
                fTextBoxControl.ForeColor = StyleController.InActiveForeColor;
            }
            base.OnLeave(e);
        }        
      
        #endregion    

        #region Component Designer generated code
        /// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.fTextBoxControl = new SGBControls.Editors.SGBBaseTextBox();
            this.SuspendLayout();
            // 
            // fTextBoxControl
            // 
            this.fTextBoxControl.BorderStyle = System.Windows.Forms.BorderStyle.None;
            this.fTextBoxControl.Dock = System.Windows.Forms.DockStyle.Fill;
            this.fTextBoxControl.Location = new System.Drawing.Point(4, 4);
            this.fTextBoxControl.Name = "fTextBoxControl";
            this.fTextBoxControl.Size = new System.Drawing.Size(120, 13);
            this.fTextBoxControl.TabIndex = 0;
            this.fTextBoxControl.SizeChanged += new System.EventHandler(this.TextBox_SizeChanged);
            // 
            // SGBTextBox
            // 
            this.BackColor = System.Drawing.SystemColors.Window;
            this.Controls.Add(this.fTextBoxControl);
            this.Name = "SGBTextBox";
            this.Padding = new System.Windows.Forms.Padding(4);
            this.Size = new System.Drawing.Size(128, 22);
            this.ResumeLayout(false);
            this.PerformLayout();

		}

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }
		#endregion		
    
	}
}
